package jp.sourceforge.akjrcp.text_douga;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import jp.sourceforge.akjrcp.text_douga.video.TextDougaVideoUtils;
import jp.sourceforge.akjrcp.util.image.ImageUtils;

public class VideoSystem {
	
	public static Log log = LogFactory.getLog(VideoSystem.class);

	private List<VideoData> videoDatas = new ArrayList<VideoData>();

	private List<ItemData> itemDatas = new ArrayList<ItemData>();

	private List<EffectData> effectDatas = new ArrayList<EffectData>();

	private double maxTime;

	private DougaPreference videoPreference = new DougaPreference();

	private ItemSorter itemSorter=new ItemSorter();
	private boolean cancelling;
	
	public int countItems(){
		return itemDatas.size();
	}
	public VideoOutInfo[] writeDatas(File dir) throws IOException {
		List<VideoOutInfo> videoOutInfos = new ArrayList<VideoOutInfo>();
		int maxframe = (int) (maxTime * videoPreference.getFps());	//TODO BIG
		VideoData[] datas = getVideoDatas();

		int writed = 0;
		for (int i = 0; i < datas.length; i++) {
			int wf = 0;
			wf = datas[i].writeData(dir, videoPreference, writed + 1, maxframe);// start
			VideoOutInfo info = new VideoOutInfo(datas[i], wf);
			videoOutInfos.add(info);

			writed += wf;

			if (maxframe != 0 && writed >= maxframe) {
				log.info("over maxframe:");
				break;
			}
			DougaSystem.dougaLogger.info(Messages.getString("log.finish_video_sequence")+":"+(i+1)+" of "+datas.length);
			
			if(cancelling){
				log.info("cancelled");
				return null;
			}
		}

		return videoOutInfos.toArray(new VideoOutInfo[videoOutInfos.size()]);
	}
	
	public VideoOutInfo[] writeDatas(VideoWriter writer) throws IOException {
		List<VideoOutInfo> videoOutInfos = new ArrayList<VideoOutInfo>();
		int maxframe = (int) (maxTime * videoPreference.getFps());//TODO BIG
		writer.setMaxFrame(maxframe);
		VideoData[] datas = getVideoDatas();

		int writed = 0;
		for (int i = 0; i < datas.length; i++) {
			int wf = 0;
			log.info("start write VideoData "+i+" "+datas[i]);
			wf = datas[i].writeData(writer, videoPreference);// start
			VideoOutInfo info = new VideoOutInfo(datas[i], wf);
			videoOutInfos.add(info);

			writed += wf;

			if (maxframe != 0 && writed >= maxframe) {
				log.info("over maxframe:");
				break;
			}
			DougaSystem.dougaLogger.info(Messages.getString("log.finish_video_sequence")+":"+(i+1)+" of "+datas.length);
			
			if(cancelling){
				log.info("cancelled");
				return null;
			}
		}

		writer.close();
		
		return videoOutInfos.toArray(new VideoOutInfo[videoOutInfos.size()]);
	}

	

	public void writeItemAndEffect(File dir, VideoOutInfo[] outInfos) throws IOException {
		EffectData[] ef = effectDatas.toArray(new EffectData[effectDatas.size()]);
		
		for (int k = 0; k < ef.length; k++) {
			ef[k].setExportDir(dir);
			log.trace(ef[k]);
		}
		
		// TODO get dir from outinfo
		int index = 1;
		ItemData[] items = getSortedItemDatas();
		for (int i = 0; i < outInfos.length; i++) {
			int maxframe = outInfos[i].getFrames();
			for (int j = 0; j < maxframe; j++) {
				String imagePath=getFrameFilePath(dir, index);

				ImageObject imageObject=null;
				if (new File(imagePath).exists()) {
					boolean imageModified=false;
					try {
						imageObject = new ImageObject(imagePath);
						
						//TODO sort
						//ITEMS
						
						for (int k = 0; k < items.length; k++) {
							boolean writed=items[k].writeFrame(videoPreference, imageObject,
									index);
							if(writed){
								imageModified=true;
							}
						}
						
						//EFFECTS
						EffectData[] effects = effectDatas.toArray(new EffectData[effectDatas.size()]);
						
						for (int k = 0; k < effects.length; k++) {
							
							boolean writed=effects[k].writeFrame(videoPreference, imageObject,
									index);
							if(writed){
								imageModified=true;
							}
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					if(imageModified){
					ImageUtils.writeJpegWithQuality(imageObject.getImage(), new File(imagePath), 1.0f);
					
					}
				} else {
					log.warn("img not found:" + imageObject.getImage());
				}
				index++;
				
				if(cancelling){
					log.info("cancelled");
					return;
				}
			}
		}
	}

	//TODO change 
	public static String getFrameFilePath(File exportDir, int index) {
		String path = exportDir.getAbsolutePath() + "\\"
				+ TextDougaVideoUtils.toFileName("", index, 5, "jpg");// todo;
		return path;
	}
	
	

	public double getMaxTime() {
		return maxTime;
	}

	public void setMaxTime(double maxTime) {
		this.maxTime = maxTime;
	}

	public void setEffectDatas(List<EffectData> effectDatas) {
		this.effectDatas = effectDatas;
	}

	public void addVideoData(VideoData videoData) {
		videoDatas.add(videoData);
	}

	public VideoData[] getVideoDatas() {
		return videoDatas.toArray(new VideoData[videoDatas.size()]);
	}

	public void addItemData(ItemData itemData) {
		itemDatas.add(itemData);
	}

	public ItemData[] getSortedItemDatas() {
		ItemData[] data=itemDatas.toArray(new ItemData[itemDatas.size()]);
		Arrays.sort(data,itemSorter);
		return data;
	}
	
	public class ItemSorter implements Comparator<ItemData>{

		public int compare(ItemData o1, ItemData o2) {
			// TODO Auto-generated method stub
			return o1.getZ()-o2.getZ();
		}
		
	}

	public void addEffectData(EffectData effectData) {
		effectDatas.add(effectData);
	}

	public EffectData[] getEffectDatas() {
		return effectDatas.toArray(new EffectData[effectDatas.size()]);
	}

	public DougaPreference getDougaPreference() {
		return videoPreference;
	}

	public void setDougaPreference(DougaPreference videoPreference) {
		this.videoPreference = videoPreference;
	}



	public boolean isCancelling() {
		return cancelling;
	}



	public void setCancelling(boolean cancelling) {
		this.cancelling = cancelling;
	}
}
